/*
 * Copyright (C) Francisco Morero Peyrona. All rights reserved.
 *
 * This software is published under the terms of Open Source
 * License version 1.1, a copy of which has been included with this
 * distribution in the License.txt file.
 */

package jdbcmanager.app;

import java.util.*;
import java.io.*;

import java.awt.*;
import javax.swing.*;

import jdbcmanager.dbtools.*;
import jdbcmanager.dbtools.dbconnect.*;
import jdbcmanager.swing.*;
import jdbcmanager.swing.table.*;

/**
 * Saves and retrieves a session.
 * <p>
 * Called by the SqlVerboser toolbar buttons. 
 * 
 * @author Francisco Morero Peyrona
 */
final class Session
{   
   private final static String sKEY_DRIVER   = "Driver";
   private final static String sKEY_URL      = "URL";
   private final static String sKEY_FRAMES   = "Frames";
   private final static String sKEY_USER     = "User";
   private final static String sKEY_PASSWORD = "Password";
   
   // Key stored in files indicating that user does not want to save a passsword 
   // It is needed to diferentiate between 'password not saved' and 'saved password is empty password'
   private final static String sASK_PASSWORD = "<AskForPassword>";
   
   private final static String sSEP = "\n\r";
   
   //-------------------------------------------------------------------------//
   
   /**
    * Saves current session: connection and internal frames.
    */
   public static void save()
   {
      JLabel     lblFileName = new JLabel( "File name" );
      JTextField txtFileName = new JTextField();
      JCheckBox  chkSavePass = new JCheckBox( "Save password (care: not secure)");
                 chkSavePass.setSelected( true ); 
                 
      JPanel     pnl = new JPanel( new BorderLayout( 0,7 ) );
                 pnl.add( lblFileName, BorderLayout.NORTH  );
                 pnl.add( txtFileName, BorderLayout.CENTER );
                 pnl.add( chkSavePass, BorderLayout.SOUTH  );
                 
      JxDialog   dlg = new JxDialog( "Save session" );
                 dlg.getContentPane().add( pnl, BorderLayout.CENTER );
                 dlg.pack();
                 dlg.center();
                 dlg.setVisible( true );
      
      if( dlg.getCloseOption() == JxDialog.ACCEPTED )
      {
         String sFileName = txtFileName.getText().trim();
           
         if( sFileName.length() > 0 )
         {
            sFileName = StrWise.normalizeFileName( sFileName );
            
            if( sFileName.length() > 0 )
            {
               String   sDriver  = DbUtil.getAgentDBMS().getDriverId();
               String   sURL     = DbUtil.getURL();
               String   sUser    = DbUtil.getUser();
               String   sPass    = chkSavePass.isSelected() ? DbUtil.getPassword() : sASK_PASSWORD;
               String[] asSerial = App.getFrameMain().serializeSession();
               File     fOut     = new File( App.getUserDir(), sFileName.trim() + App.sSESSION_FILE_EXT );
   
               if( ! fOut.exists() || App.confirmDialog( "Confirm overwrite", "File already exists. Overwrite?" ) )
                  save2File( fOut, sDriver, sURL, sUser, sPass, asSerial );
            }
            else
            {
               App.showMessage( "Wrong file name", "File name contains only unaccepted characters: use only letters, digits and '_'" );
            }
         }
         else
         {
            App.showMessage( "Wrong file name", "File name can not be empty." );
         }
      }
   }
   
   /**
    * Retrieves a previously saved session.
    */
   public static void load( String sFileName )
   {
      Properties session = null;
      File       file    = null;
      
      if( sFileName != null )
         file = new File( App.getUserDir(), sFileName + App.sSESSION_FILE_EXT );
      else
         file = ask4File();
      
      if( file != null )
      {
         session = getSession( file );
      
         if( session != null )
         {
            String sDriver = session.getProperty( sKEY_DRIVER   );
            String sURL    = session.getProperty( sKEY_URL      );
            String sUser   = session.getProperty( sKEY_USER     );
            String sPass   = session.getProperty( sKEY_PASSWORD );
            String sFrames = session.getProperty( sKEY_FRAMES   );
            
            if( sPass.equals( sASK_PASSWORD ) )
               sPass = App.getStringUsingDialog( "Enter password", "Password", "", false );
            
            if( sPass != null )
            {
               if( sDriver != null && sURL != null && sPass != null )
               {
                  App.connect2DBMS( new ConnectionDefinition( sDriver, sURL, sUser, sPass, null ) );
                  
                  if( sFrames != null )
                     App.getFrameMain().deserializeSession( StrWise.string2Array( sFrames, sSEP ) );
               }
               else
               {
                  App.showMessage( "File corrupted", "Can't retrieve session: most probably the file is corrupted" );
               }
            }
            else
            {
               App.showMessage( "Canceled", "Password not entered: retrieve session canceled" );
            }
         }
      }
   }
   
   /**
    * Return <code>true</code> if there is at least one previously saved session, otherwise return <code>false</code>
    * 
    * @return <code>true</code> if there is at least one previously saved session, otherwise return <code>false</code>
    */
   public static boolean areThereSavedSessions()
   {
      return getSavedSessions().length > 0;
   }
   
   //-------------------------------------------------------------------------//

   private static void save2File( File fOut, String sDriver, String sURL, String sUser, String sPass, String[] asSerial )
   {
      Properties session = new Properties();
      
      // Transforms all serialized insternal frames in one single entry in the properties file
      StringBuffer sb = new StringBuffer( 2048 );
      
      for( int n = 0; n < asSerial.length; n++ )
         sb.append( asSerial[n] ).append( sSEP );
      
      // Saves properties into file
      session.put( sKEY_DRIVER  , sDriver       );
      session.put( sKEY_URL     , sURL          );
      session.put( sKEY_USER    , sUser         );
      session.put( sKEY_PASSWORD, sPass         );
      session.put( sKEY_FRAMES  , sb.toString() );
      
      try
      {            
         FileOutputStream fos = new FileOutputStream( fOut );
   
         session.store( fos, " "+ App.sAPP_TITLE +" - Serialized Session File." );         
         fos.close();
      }
      catch( Exception exc )
      {
         App.showDebugException( exc );
      }
   }
   
   private static Properties getSession( File file )
   {
      Properties session = null;
      
      if( file.exists() && file.isFile() )
      {
         try
         {
            FileInputStream fis = new FileInputStream( file );
      
            session = new Properties();
            session.load( fis );
         }
         catch( IOException exc )
         {
            App.showException( exc, "Error reading file" );
         }
      }
      else
      {
         App.showMessage( "Error loading session", "File \""+ file.getAbsolutePath() +"\" does not exists." );
      }
      
      return session;
   }
   
   private static File ask4File()
   {
      File[] aFile = getSavedSessions();
      File   file  = null;
      
      if( aFile.length > 0 )
      {
         JxTableMap table = new JxTableMap( new String[] {"Session","Date"} );
         
         for( int n = 0; n < aFile.length; n++ )
            table.addRow( aFile[n].getName().substring( 0, aFile[n].getName().lastIndexOf( '.' ) ), new Date( aFile[n].lastModified() ) );
         
         table.adjustColumnsWidth();
         table.setRowSelectionInterval( 0,0 );
         
         JxDialog dialog = new JxDialog( "Select session to be retrieved" ); 
                  dialog.getContentPane().add( new JScrollPane( table ), BorderLayout.CENTER );
                  dialog.pack();
                  dialog.center();
                  dialog.setVisible( true );
                  
         if( dialog.getCloseOption() == JxDialog.ACCEPTED && table.getSelectedRow() > -1 )
         {
            String sFileName = (String) table.getValueAt( table.getSelectedRow(), 0 );
            file = new File( App.getUserDir(), sFileName + App.sSESSION_FILE_EXT );
         }
      }
      else
      {
         App.showMessage( "No session to retrieve", "Can't retrieve: there is no previously saved session." );
      }
      
      return file;
   }
   
   private static File[] getSavedSessions()
   {
      File[] aFile = App.getUserDir().listFiles( new FileFilter()
      {
         public boolean accept( File f )  { return f.getName().endsWith( App.sSESSION_FILE_EXT ); }
      } );
         
      return aFile;
   }
}
